 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "common.h"
#include "database.h"
#include <pthread.h>  // 线程

// 抽象客户端
typedef struct client {
	int sock_fd;
	int port;
	int type;
	int userID;
	int loginFlag;
	int permission; // 权限设置
	char ip[16]; // 192.168.1.109
}Client;

static int listen_fd;
static void * deal_client(void *arg);

/*
	使服务器处于监听状态
*/
int server_listen(const char *ip, const int port, int backlog)
{
	
	int ret;
	// 创建socket
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_fd == -1) {
		perror("socket");
		return -1;
	}
	
	// 绑定自己的IP
	struct sockaddr_in local_addr;
	local_addr.sin_family = AF_INET; // 协议族
	local_addr.sin_port = htons(port); // 指定服务器的端口号
	local_addr.sin_addr.s_addr = inet_addr(ip); // 指定服务器IP地址
	
	ret = bind(listen_fd, (struct sockaddr *)&local_addr, sizeof(local_addr));
	if (ret == -1) {
		perror("bind");
		return -1;
	}
	// 服务器listen客户端
	listen(listen_fd, backlog);
	return listen_fd;
}

/*
	获取客户端
*/

int sever_run()
{
	int ret;
	// 服务器接收连接
	struct sockaddr_in client_addr;
	bzero(&client_addr, sizeof(client_addr));
	socklen_t len = sizeof(client_addr);
	int client_sock_fd;
	while (1) {
		//=====================取出一个客户端连接=================================
		client_sock_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len); 
		if (client_sock_fd == -1) {
			perror("accept");
			return -1;
		}
		//=====================创建线程============================================
		pthread_t tid;
		Client *client = malloc(sizeof(Client)); // 创建客户端对象
		if (client == NULL) { // 代码健壮性
			close(client_sock_fd);
			continue;
		}
		bzero(client, sizeof(Client));
		client->sock_fd = client_sock_fd; // 填充sock fd
		client->port = ntohs(client_addr.sin_port); // 填端口
		strcpy(client->ip, inet_ntoa(client_addr.sin_addr)); // 填IP
		printf("Client %s connect server succeful\n", client->ip);
		
		if (0 != pthread_create(&tid, NULL, deal_client, (void *)client)) {// 创建线程
			printf("thread create fail\n");
			continue;
		} 
		pthread_detach(tid); // 分离线程,当线程退出时自动回收其资源
		//sleep(5);
		//break;
	}
}
int server_close()
{
	// 关闭连接
	close(listen_fd);
    return 0;
}

/*
   执行任务(服务客户端)
*/
static char func_desc[][10] = {"登录","注册","查询"};
static void * deal_client(void *arg)
{
	Client * client = (Client *)arg;
	ConnPack pack; // 声明接收数据包变量
	int ret;
	char passwd[16]; //
	while (1) {
		//===============从客户端读取请求数据==========================
		memset(&pack, 0, sizeof(pack));
		ret = read(client->sock_fd, &pack, sizeof(pack));
		if (ret == -1) {
			perror("read");
			break;
		} else if (ret == 0) {
			printf("客户端 [%s] 强制退出\n", client->ip);
			break;
		}
		printf("server recv [%s] package ok\n", client->ip);
		
		//================客户端的请求处理===============================
		if(strcmp(pack.header, "PARK") != 0) {   // 协议头判断
			// 对客户端响应
			ret = write(client->sock_fd, "protocal error",strlen("protocal error"));
			if (ret == -1) {
				perror("write");	
			}
			break;
		}
		
		client->type = pack.type;
		client->userID = pack.userID;
		printf("客户端请求%s处理\n", func_desc[pack.type - 1]);
		
		switch(pack.type) {
			case LOGIN:		
				printf("登录账户: %s, %s\n", pack.name, pack.passwd);
				bzero(passwd, sizeof(passwd));
				if (0 == mysql_select_passwd_by_name(pack.name, passwd)) {
					if (0 == strcmp(passwd, pack.passwd)) {
						printf("登录成功\n");
						client->loginFlag = 1; // 登录状态
						//client->permission = ;
						
						// 对客户端响应
						ret = write(client->sock_fd, "login ok",strlen("login ok"));
						if (ret == -1) {
							perror("write");
							break;
						}
					} else {
						// 对客户端响应
						ret = write(client->sock_fd, "passwd error",strlen("passwd error"));
						if (ret == -1) {
							perror("write");
							break;
						}
					}
				} else {
					printf("登录失败\n");
					// 对客户端响应
					ret = write(client->sock_fd, "login error",strlen("login error"));
					if (ret == -1) {
						perror("write");
						break;
					}
				}
			break;
			
			case REGISTE:
			break;
			case LOOKUP:
			break;
			default:
			break;
		}
		//===============检查退出条件=============================
		//break; // 执行一次，测试使用
	}
	close(client->sock_fd); // 关闭与客户端的连接
	free(client); // 释放client对象
	pthread_exit(NULL);
}